/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    can.c
  * @brief   This file provides code for the configuration
  *          of the CAN instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */


/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/

/* USER CODE BEGIN 0 */
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "bsp.h"
#include "utility.h"
#include "tim.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_tim.h"



CAN_HandleTypeDef hcan;
CAN_TxHeaderTypeDef hcan_txheader;    /* 发送参数句柄 */
CAN_RxHeaderTypeDef hcan_rxheader;    /* 接收参数句柄 */
uint8_t rxbuf[8];
/* USER CODE END 0 */
extern bool canRxEvent;
extern CAN_RxHeaderWithMsgDef RxMsg;

uint8_t can_init(uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode);

/* CAN init function */
void MX_CAN_Init(void)
{

  uint32_t filterId = 0x00000000, filterMask = 0X00000000;               /* 过滤器标识符及掩码 */
  can_init(CAN_SJW_1TQ, CAN_BS2_8TQ, CAN_BS1_9TQ, 4, CAN_MODE_NORMAL); /* CAN普通模式初始化, 回环模式, 波特率500Kbps */
  can_filter_config(filterId, filterMask);

}

void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspInit 0 */

  /* USER CODE END CAN1_MspInit 0 */
    /* CAN1 clock enable */
    __HAL_RCC_CAN1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**CAN GPIO Configuration
    PA11     ------> CAN_RX
    PA12     ------> CAN_TX
    */
    GPIO_InitStruct.Pin = CAN_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(CAN_RX_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = CAN_TX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(CAN_TX_PORT, &GPIO_InitStruct);

  /* USER CODE BEGIN CAN1_MspInit 1 */
  //GD32似乎无法硬件退出sleep模式，造成超时错误，故需要手动清除位来兼容
	CLEAR_BIT(canHandle->Instance->MCR, CAN_MCR_SLEEP);      
  /* USER CODE END CAN1_MspInit 1 */
  }
}

void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
{

  if(canHandle->Instance==CAN1)
  {
  /* USER CODE BEGIN CAN1_MspDeInit 0 */

  /* USER CODE END CAN1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CAN1_CLK_DISABLE();

    /**CAN GPIO Configuration
    PA11     ------> CAN_RX
    PA12     ------> CAN_TX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);

  /* USER CODE BEGIN CAN1_MspDeInit 1 */

  /* USER CODE END CAN1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
void printCANTxMsg(CAN_TxHeaderWithMsgDef *txmsg)
{
  printf("can send data: %#X | ", txmsg->header.StdId);
  for(uint8_t i = 0; i < txmsg->header.DLC; i++){
    printf("%#X ",txmsg->msg[i]);
  }
  printf("\r\n");
}

void printCANRxMsg(CAN_RxHeaderWithMsgDef *rxmsg)
{
  printf("\r\n");
  printf("can receive data: %#X | ", rxmsg->header.StdId);
  for(uint8_t i = 0; i < rxmsg->header.DLC; i++){
    printf("%#X ",rxmsg->msg[i]);
  }
  printf("\r\n");
}




/**
 * @brief       CAN初始化
 * @param       tsjw    : 重新同步跳跃时间单元.范围: 1~3;
 * @param       tbs2    : 时间段2的时间单元.范围: 1~8;
 * @param       tbs1    : 时间段1的时间单元.范围: 1~16;
 * @param       brp     : 波特率分频器.范围: 1~1024;
 *   @note      以上4个参数, 在函数内部会减1, 所以, 任何一个参数都不能等于0
 *              CAN挂在APB1上面, 其输入时钟频率为 Fpclk1 = PCLK1 = 36Mhz
 *              tq     = brp * tpclk1;
 *              波特率 = Fpclk1 / ((tbs1 + tbs2 + 1) * brp);
 *              我们设置 can_init(1, 8, 9, 4, 1), 则CAN波特率为:
 *              36M / ((8 + 9 + 1) * 4) = 500Kbps
 *
 * @param       mode    : CAN_MODE_NORMAL,  普通模式;
                          CAN_MODE_LOOPBACK,回环模式;
 * @retval      0,  初始化成功; 其他, 初始化失败;
 */
uint8_t can_init(uint32_t tsjw, uint32_t tbs2, uint32_t tbs1, uint16_t brp, uint32_t mode)
{
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = brp;                /* 分频系数(Fdiv)为brp+1 */
  hcan.Init.Mode = mode;                    /* 模式设置 */
  hcan.Init.SyncJumpWidth = tsjw;           /* 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1TQ~CAN_SJW_4TQ */
  hcan.Init.TimeSeg1 = tbs1;                /* tbs1范围CAN_BS1_1TQ~CAN_BS1_16TQ */
  hcan.Init.TimeSeg2 = tbs2;                /* tbs2范围CAN_BS2_1TQ~CAN_BS2_8TQ */
  hcan.Init.TimeTriggeredMode = DISABLE;    /* 非时间触发通信模式 */
  hcan.Init.AutoBusOff = DISABLE;           /* 软件自动离线管理 */
  hcan.Init.AutoWakeUp = DISABLE;           /* 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位) */
  hcan.Init.AutoRetransmission = ENABLE;    /* 禁止报文自动传送 */
  hcan.Init.ReceiveFifoLocked = DISABLE;    /* 报文不锁定,新的覆盖旧的 */
  hcan.Init.TransmitFifoPriority = DISABLE; /* 优先级由报文标识符决定 */
  if (HAL_CAN_Init(&hcan) != HAL_OK)
  {
    return 1;
  }

#if CAN_RX0_INT_ENABLE

  /* 使用中断接收 */
  __HAL_CAN_ENABLE_IT(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);            /* FIFO0消息挂号中断允许 */
  HAL_NVIC_EnableIRQ(CAN_RX_IRQn);                          /* 使能CAN中断 */
  HAL_NVIC_SetPriority(CAN_RX_IRQn, CAN_RX_Priority, 0);    /* 抢占优先级1，子优先级0 */
#endif

 

  /* 启动CAN外围设备 */
  if (HAL_CAN_Start(&hcan) != HAL_OK)
  {
    return 1;
  }


  return 0;
}

uint32_t can_filter_config(uint32_t filterId, uint32_t filterMask)
{
  CAN_FilterTypeDef sFilterConfig;

  /* 配置CAN过滤器 */
  sFilterConfig.FilterBank = 0;                             /* 过滤器0 */
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterIdHigh = ((filterId >> 16) & 0x00FF);                      /* 32位ID */
  sFilterConfig.FilterIdLow = filterId & 0x00FF;
  sFilterConfig.FilterMaskIdHigh = ((filterMask >> 16) & 0x00FF);                  /* 32位MASK */
  sFilterConfig.FilterMaskIdLow = filterMask & 0x00FF;
  sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;    /* 过滤器0关联到FIFO0 */
  sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;       /* 激活滤波器0 */
  sFilterConfig.SlaveStartFilterBank = 14;

  /* 过滤器配置 */
  if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
  {
    return 1;
  }
  return 0;
}

/**
 * @brief       CAN 发送一组数据
 *   @note      发送格式固定为: 标准ID, 数据帧
 * @param       id      : 标准ID(11位)
 * @retval      发送状态 0, 成功; 1, 失败;
 */
uint8_t can_send_msg(uint32_t id, uint8_t *msg, uint8_t len, uint32_t delay)
{
  uint32_t TxMailbox = CAN_TX_MAILBOX0;
  hcan_txheader.StdId = id;         /* 标准标识符 */
//  g_canx_txheader.ExtId = id;         /* 扩展标识符(29位) */
  hcan_txheader.IDE = CAN_ID_STD;   /* 使用标准帧 */
  hcan_txheader.RTR = CAN_RTR_DATA; /* 数据帧 */
  hcan_txheader.DLC = len;

  if (HAL_CAN_AddTxMessage(&hcan, &hcan_txheader, msg, &TxMailbox) != HAL_OK) /* 发送消息 */
  {
    return 1;
  }
  uint32_t timeout = HAL_GetTick() + delay;
  while (HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3){
    printf("waiting transmit complete.... timeout in %dms\r\n",HAL_GetTick());
    if(HAL_GetTick() >= timeout){
      return 1;
    }
    HAL_Delay(10);
  }; /* 等待发送完成,所有邮箱为空 */
  return 0;
}

/**
 * @brief       CAN 接收数据查询
 *   @note      接收数据格式固定为: 标准ID, 数据帧
 * @param       id      : 要查询的 标准ID(11位)
 * @param       buf     : 数据缓存区
 * @retval      接收结果
 *   @arg       0   , 无数据被接收到;
 *   @arg       其他, 接收的数据长度
 */
uint8_t can_receive_msg(uint8_t *rxbuf)
{
  if (HAL_CAN_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) == 0)     /* 没有接收到数据 */
  {
    printf("no msg received\r\n");
    return 0;
  }

  if (HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &hcan_rxheader, rxbuf) != HAL_OK)  /* 读取数据 */
  {
    return 0;
  }
   
  return hcan_rxheader.DLC;
}

uint8_t can_receive(CAN_HandleTypeDef *canx, uint32_t fifo, CAN_RxHeaderWithMsgDef *rxmsg)
{
  if (HAL_CAN_GetRxFifoFillLevel(canx, fifo) == 0)     /* 没有接收到数据 */
  {
    printf("no msg received\r\n");
    return 0;
  }

  if (HAL_CAN_GetRxMessage(canx, fifo, &rxmsg->header, rxmsg->msg) != HAL_OK)  /* 读取数据 */
  {
    return 0;
  }
   
  return rxmsg->header.DLC;
}



void TestCANProcess(const void* arg)
{
    uint8_t key;
    uint8_t i = 0, t = 0;
    uint8_t cnt = 0;
    uint8_t canbuf[8];
    uint8_t res;
    uint8_t mode      = 1;                                                 /* CAN工作模式: 0,普通模式; 1,环回模式 */
    // uint32_t filterId = 0x6F000000, filterMask = 0X00FFFFFF;               /* 过滤器标识符及掩码 */
    uint32_t filterId = 0x00000000, filterMask = 0X00000000;               /* 过滤器标识符及掩码 */
    can_init(CAN_SJW_1TQ, CAN_BS2_8TQ, CAN_BS1_9TQ, 4, CAN_MODE_LOOPBACK); /* CAN普通模式初始化, 回环模式, 波特率500Kbps */
    can_filter_config(filterId, filterMask);
    printText("LoopBack Mode\r\n", RED);
    uint32_t recv_times = 0;

    while(1)
    {
        key = Key_GetNum();
        if (key == KEY0_PRES) /* KEY0按下,发送一次数据 */
        {
            printText("send data:\r\n", RED);
            for (i = 0; i < 8; i++) {
                canbuf[i] = cnt + i;      /* 填充发送缓冲区 */
                printNum(canbuf[i], RED); /* 显示数据 */
            }

            res = can_send_msg(filterId >> CAN_FILTER_SHFT, canbuf, 8, 3000); /* 发送8个字节 */

            if (res) {
                printText("send Failed\r\n", RED); /* 提示发送失败 */
            } else {
                printText("send OK\r\n", RED); /* 提示发送成功 */
            }
        } else if (key == KEY1_PRES) /* WK_UP按下，改变CAN的工作模式 */
        {
            mode = !mode;

            if (mode == 0) /* 普通模式，需要2个开发板 */
            {
                can_init(CAN_SJW_1TQ, CAN_BS2_8TQ, CAN_BS1_9TQ, 4, CAN_MODE_NORMAL); /* CAN普通模式初始化, 普通模式, 波特率500Kbps */
                printText("Normal Mode \r\n", RED);
            } else /* 回环模式,一个开发板就可以测试了. */
            {
                can_init(CAN_SJW_1TQ, CAN_BS2_8TQ, CAN_BS1_9TQ, 4, CAN_MODE_LOOPBACK); /* CAN普通模式初始化, 回环模式, 波特率500Kbps */
                printText("LoopBack Mode\r\n", RED);
            }
        }

        #if CAN_RX0_INT_ENABLE == 1
            if (canRxEvent)                   /* 接收到有数据 */
            {
                printf("id:%#X\r\n", RxMsg.header.StdId);
                printf("ide:%d\r\n", RxMsg.header.IDE);
                printf("rtr:%d\r\n", RxMsg.header.RTR);
                printf("len:%d\r\n", RxMsg.header.DLC);

                printf("rxbuf[0]:%d\r\n", RxMsg.msg[0]);
                printf("rxbuf[1]:%d\r\n", RxMsg.msg[1]);
                printf("rxbuf[2]:%d\r\n", RxMsg.msg[2]);
                printf("rxbuf[3]:%d\r\n", RxMsg.msg[3]);
                printf("rxbuf[4]:%d\r\n", RxMsg.msg[4]);
                printf("rxbuf[5]:%d\r\n", RxMsg.msg[5]);
                printf("rxbuf[6]:%d\r\n", RxMsg.msg[6]);
                printf("rxbuf[7]:%d\r\n", RxMsg.msg[7]);
                canRxEvent = false;
                ++recv_times;
                printf("recv_time = %d\r\n", recv_times);
            }
        #else
            uint8_t rxlen = can_receive_msg(rxbuf);
            if(rxlen > 0)
            {
                printf("id:%#X\r\n", hcan_rxheader.StdId);
                printf("ide:%d\r\n", hcan_rxheader.IDE);
                printf("rtr:%d\r\n", hcan_rxheader.RTR);
                printf("len:%d\r\n", rxlen);

                printf("rxbuf[0]:%d\r\n", rxbuf[0]);
                printf("rxbuf[1]:%d\r\n", rxbuf[1]);
                printf("rxbuf[2]:%d\r\n", rxbuf[2]);
                printf("rxbuf[3]:%d\r\n", rxbuf[3]);
                printf("rxbuf[4]:%d\r\n", rxbuf[4]);
                printf("rxbuf[5]:%d\r\n", rxbuf[5]);
                printf("rxbuf[6]:%d\r\n", rxbuf[6]);
                printf("rxbuf[7]:%d\r\n", rxbuf[7]);
                ++recv_times;
                printf("recv_time = %d\r\n", recv_times);
            }
        #endif 
        t++;
        HAL_Delay(10);

        if (t == 20) {
            LED2_TOGGLE; /* 提示系统正在运行 */
            t = 0;
        }
    }
}

/* USER CODE END 1 */
